#include "cf_includes.h"

inline DWORD FtoDW( FLOAT f ) { return *((DWORD*)&f); }

CCF_Particles::CCF_Particles(void)
{
  m_direction = D3DXVECTOR3( 0, 1, 0 );
  m_slowCoeficient = 0.1;
  m_dropCoeficient = 0.1;
}

CCF_Particles::~CCF_Particles(void)
{
}

void CCF_Particles::Initialize( LPDIRECT3DDEVICE9 device, const WCHAR* texture )
{
  m_device = device;
  WCHAR fullpath[ MAX_PATH ];
  GetFullPathName( texture, MAX_PATH, fullpath, NULL );

  D3DXCreateTextureFromFile( m_device, fullpath, &m_texture );

  m_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  m_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);


  m_device->CreateVertexBuffer( 2048 * sizeof(Vertex),
    D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY | D3DUSAGE_POINTS, 
    Vertex::FVF_Flags, D3DPOOL_DEFAULT, &m_vertexBuffer, NULL );

  for( int i = 0; i < MAX_PARTICLES; ++i )
  {
    m_particles[ i ].Vec = EMPTY_VECTOR;
  }
}

void CCF_Particles::Update( double time )
{
  for( int i = 0; i < MAX_PARTICLES; ++i )
  {
    if( m_particles[ i ].Vec == EMPTY_VECTOR )
    {
      double other = D3DXVec3Length( &m_direction );
      m_particles[ i ].Pos = EMPTY_VECTOR;

      m_particles[ i ].Vec.x = (1.0f - m_dropCoeficient)*m_direction.x + other*(m_dropCoeficient - RANDOM(0.0f, 2*m_dropCoeficient ));
      m_particles[ i ].Vec.y = (1.0f - m_dropCoeficient)*m_direction.y + other*(m_dropCoeficient - RANDOM(0.0f, 2*m_dropCoeficient ));
      m_particles[ i ].Vec.z = (1.0f - m_dropCoeficient)*m_direction.z + other*(m_dropCoeficient - RANDOM(0.0f, 2*m_dropCoeficient ));

      m_particles[ i ].Color = D3DCOLOR_COLORVALUE( RANDOM( 0.0f, 1.0f ),
        RANDOM( 0.0f, 1.0f ), RANDOM( 0.0f, 1.0f ), 1.0f );
    }
    else
    {
      m_particles[ i ].Pos += time*m_particles[ i ].Vec;
      m_particles[ i ].Vec -= m_slowCoeficient*m_particles[ i ].Vec;

      if( D3DXVec3LengthSq( &m_particles[ i ].Vec ) < m_slowCoeficient )
      {
        m_particles[ i ].Vec = EMPTY_VECTOR;
      }
    }
  }
}

void CCF_Particles::Render()
{
  m_device->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
  m_device->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  m_device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
  m_device->SetRenderState( D3DRS_POINTSPRITEENABLE, TRUE );   
  m_device->SetRenderState( D3DRS_POINTSCALEENABLE,  TRUE );    
  m_device->SetRenderState( D3DRS_POINTSIZE,     FtoDW(1.0f) ); 
  m_device->SetRenderState( D3DRS_POINTSIZE_MIN, FtoDW(1.0f) );  
  m_device->SetRenderState( D3DRS_POINTSCALE_A,  FtoDW(0.0f) ); 
  m_device->SetRenderState( D3DRS_POINTSCALE_B,  FtoDW(0.0f) ); 
  m_device->SetRenderState( D3DRS_POINTSCALE_C,  FtoDW(1.0f) ); 

  Vertex *pPointVertices;

  m_vertexBuffer->Lock( 0, MAX_PARTICLES * sizeof(Vertex), (void**)&pPointVertices, 0 );

  for( int i = 0; i < MAX_PARTICLES; ++i )
  {
    pPointVertices->Pos = m_particles[ i ].Pos;
    pPointVertices->Color = m_particles[i].Color;
    pPointVertices++;
  }

  m_vertexBuffer->Unlock();

  m_device->SetTexture( 0, m_texture );
  m_device->SetStreamSource( 0, m_vertexBuffer, 0, sizeof(Vertex) );
  m_device->SetFVF( Vertex::FVF_Flags );
  m_device->DrawPrimitive( D3DPT_POINTLIST, 0, MAX_PARTICLES/2 );

  m_device->SetRenderState( D3DRS_POINTSPRITEENABLE, FALSE );
  m_device->SetRenderState( D3DRS_POINTSCALEENABLE,  FALSE );
  m_device->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
  m_device->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
}
